<script>
  import $ from '../dfish.js'
  import WidgetAbs from './WidgetAbs.vue'
  import SrcParent from './SrcParent.vue'
  import Pop from './Pop.vue'
  import Img from './Img.vue'

  import {
    h,
    mergeProps
  } from 'vue'

  import PreloadDialog from '../preload/PreloadDialog.vue'
  import TemplateAlert from '../template/TemplateAlert.vue'
  import TemplateConfirm from '../template/TemplateConfirm.vue'
  import TemplateTip from '../template/TemplateTip.vue'

  const templateHooks = {
    Alert: TemplateAlert,
    Confirm: TemplateConfirm,
    Tip: TemplateTip,
  }

  const _formatCache = {}

  export default {
    name: 'w-view',
    mixins: [SrcParent],
    provide() {
      return {
        provideView: this
      }
    },
    props: ['commands'],
    emits: ['load'],
    data() {
      return {
        isView: true,
        pops: [],
      }
    },
    beforeCreate() {
      this.popCommanders = {}
    },
    created() {
      if (this.isEntity && this != $.docView) {
        this.path = (this.ownerView.path ? this.ownerView.path + '/' : '') + (this.getKey() || this.uid)
        $.viewCache[this.path] = this
      }
    },
    methods: {
      reload() {
        this.request()
      },
      find(a) {
        const b = this.el().querySelectorAll(`[w-key="${a}"]`)
        for (let c of b) {
          if ((c = $(c)) && c.ownerView === this) return c
        }
      },
      fv(a, b) {
        let d = this.f(a)
        if (arguments.length === 2) {
          d && d.val(b)
        } else if (typeof a === 'object') {
          for (let i in a) this.fv(i, a[i])
        } else {
          return d && (d.groupFormVal ? d.groupFormVal() : d.formVal())
        }
      },
      f(a, b) {
        return this.fAll(a, b)[0]
      },
      // 获取范围内的所有表单 /@a -> name, b -> range?(elem|widget)
      fAll(a, b) {
        if (a === '*' || a == null) {
          for (var i = 0, q = this.getFormList(b, true), l = q.length, d, e, f = []; i < l; i++)
            (d = $(q[i])) && d != e && f.push(e = d);
          return f;
        }
        let dom = b ? (b.isWidget ? b.el() : b) : this.el()
        let r = $.q(':input[name="' + a + '"]', dom)
        if (!r.length) r = $.q(':input[w-name="' + a + '"]', dom)
        return $.lodash.map(r.not('.f-form-hide :input'), d => $(d))
      },
      // 获取所有表单，返回一个dom集合 /@ a -> range(widgetID, 可选，如果 range 以 !开头，表示排除), b -> 是否包含disabled的表单
      getFormList(a, b) {
        if (Array.isArray(a)) return a
        let r, f = ':input:not(button)' + (b ? '' : ':not(:disabled)')
        if (a && typeof a === 'string') {
          let d = a.charAt(0) === '!'
          let e = a.replace(/\!/g, '').split(',').map(v => `[w-key="${v}"] ${f}`)
          if (e = e.join())
            r = $.q(d ? `${f}:not(${e})` : e, this.el())
        } else {
          r = $.q(f, a ? (a.isWidget ? a.el() : a) : this.el())
        }
        return r ? $.lodash.map(r.not('.f-form-hide :input')) : []
      },
      // 获取提交数据 {name: value, ...} /@ a -> range [widgetID, 可选，如果 range 以 !开头，表示排除]
      getPostData(range) {
        let r = {}
        this.getFormList(range).forEach(a => {
          let d = a.name
          let v = a.value
          if (!d) return
          switch (a.type) {
            case 'text':
              let t = a.getAttribute('w-valuetype')
              if (t === 'number')
                v = v.replace(/[^\d\.-]/g, '')
              break
            case 'checkbox':
              if (!a.value || (!a.checked && !(a.indeterminate && a.getAttribute('w-partialsubmit'))))
                return null
              break
            case 'radio':
              if (!a.value || !a.checked)
                return null
              d = a.getAttribute('w-name') || d
              break;
            case 'select-one':
              if (a.selectedIndex < 0)
                return null;
              break;
          }
          v && (v = $.strTrim(v))
          if (d in r) {
            if (!Array.isArray(r[d]))
              r[d] = [r[d]]
            r[d].push(v)
          } else
            r[d] = v
        })
        return r
      },
      // 表单验证。如果检测到错误，将返回一个包含错误信息的数组 /@r -> range, n -> validate group name
      getValidError(range) {
        let e, q = this.getFormList(range)
        for (let i = 0, l = q.length, c, v; i < l; i++) {
          if ((c = $(q[i])) && c.isFormWidget && (v = c.getValidError())) {
            if (!e) e = []
            if (!e.find(n => n.wid == v.wid)) e.push(v)
          }
        }
        return e
      },
      // 表单验证。验证通过返回true /@ range -> validaterange
      valid(range) {
        if (this._err_ns) {
          this._err_ns.forEach(v => {
            let n = $.vueCache[v.wid]
             n && n.warn(false)
          })
        }
        let e = this.getValidError(range)
        if (e) {
          e.forEach(v => $.vueCache[v.wid].warn())
          $.vueCache[e[0].wid].showErrorTip(e[0].text)
        }
        return !(this._err_ns = e)
      },
      // @range -> 范围, original -> (设置为true，检测表单是否有修改，对照的值为初始值)
      isModified(range, original) {
        return this.getFormList(range).find(o => (o = $(o)).isModified && o.isModified(original))
      },
      // @range -> 范围, original -> (设置为true，设置为true，修改初始值)
      saveModified(range, original) {
        this.getFormList(range).forEach(o => (o = $(o)).saveModified && o.saveModified(original))
      },
      resetForm(range, empty) {
        this.getFormList(range).forEach(f => {
          let c = $(f)
          c.reset && c.reset(empty)
        })
      },
      showLoading(a) {
        this.cmd({
          type: 'Loading',
          cover: true,
          local: true,
          hide: a === false ? true : false
        })
      },
      cmdDialog(cmd, args, commander) {
        if (cmd.hide) {
          let o = this.pops.find(v => cmd.hide === true ? v.cmd.type == cmd.type : v.cmd.orientUid == cmd.hide)
          return o && this.removeDialog(o.cmd.orientUid)
        }
        if (!cmd.template && templateHooks[cmd.type]) cmd.template = templateHooks[cmd.type]
        let uid = $.uid()
        if (!cmd.orientUid) cmd.orientUid = uid
        this.pops.push({
          cmd,
          args,
          commander,
          hidden: false,
        })
        return uid
      },
      removeDialog(u) {
        this.$nextTick(() => {
          let o = this.pops.find(v => v.cmd.orientUid == u)
          if (o) {
            if (this.pops.findIndex(v => v.cmd.orientUid != u && !v.hidden) > -1) {
              o.hidden = true
            } else {
              this.pops = []
            }
          }
        })
      },
      getDialogOptions(u) {
        return this.pops.find(v => v.cmd.orientUid == u)
      },
      html_pops() {
        return [this.pops.map(p => h(Pop, {p}))]
      }
    },
    mounted() {
      if (this.isEntity) {
        this.request()
        this.trigger('load')
      }
    }
  }
</script>

<style>
  .w-view {
    position: relative;
  }

</style>
